package com.whenjun.service.core;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ifootbook.util.*;
import com.whenjun.common.LoggerParent;
import com.whenjun.dto.account.*;
import com.whenjun.dto.login.PasswordUpdate;
import com.whenjun.entity.Account;
import com.whenjun.entity.AuthPermission;
import com.whenjun.entity.AuthPermissionAccount;
import com.whenjun.service.impl.AccountServiceImpl;
import com.whenjun.service.impl.AuthPermissionAccountServiceImpl;
import com.whenjun.service.impl.AuthPermissionServiceImpl;
import com.whenjun.util.IPageUtil;
import com.whenjun.util.SaTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Auther: shirley
 * @Date: 2023/7/24 22:54
 * @Description:
 */
@Service
public class AccountUserService extends LoggerParent {

    @Autowired
    private AccountServiceImpl accountService;


    @Autowired
    private AccessLogService accessLogService;

    @Autowired
    private AuthPermissionServiceImpl authPermissionService;

    @Autowired
    private AuthPermissionAccountServiceImpl authPermissionAccountService;

    /**
     * 管理用户列表
     *
     * @param accountListReq
     * @return
     */
    @Transactional
    public IPage<AccountResp> accountList(AccountListReq accountListReq) {
        Page<Account> page = new Page<>(accountListReq.getPage(), accountListReq.getSize());
        LambdaQueryWrapper<Account> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.isNull(Account::getType);
        queryWrapper.orderByDesc(Account::getUpdateTime);

        IPage<Account> pageResp = accountService.getBaseMapper().selectPage(page, queryWrapper);

        List<AccountResp> accountResps = new ArrayList<>();

        for (Account account : pageResp.getRecords()) {
            AccountResp accountResp = new AccountResp();
            accountResp.setId(account.getId());
            accountResp.setUsername(account.getUsername());
            accountResp.setJobNo(account.getJobNo());
            accountResp.setNickname(EmptyUtil.isEmpty(account.getNickname()) ? account.getUsername() : account.getNickname());

            List<AuthPermissionDTO> authPermissions = authPermissionAccountService.getBaseMapper().selectAccountPermission(account.getId());

            accountResp.setAuthPermissions(authPermissions);
            accountResps.add(accountResp);
        }

        IPage<AccountResp> accountRespIPage = IPageUtil.trans(pageResp);
        accountRespIPage.setRecords(accountResps);

        return accountRespIPage;
    }


    /**
     * 创建账户
     *
     * @param accountAddReq
     */
    @Transactional
    public void accountAdd(AccountAddReq accountAddReq) {
        // 密码强度校验
        if (!PasswordUtil.validatePassword2(accountAddReq.getPassword())){
            throw new FootBookException("密码必须为大写英文+小写+数字+特殊符号的组合");
        }
        // 当前管理员账户
        String adminId = SaTokenUtil.getUserId();

        // 校验用户名是否存在
        LambdaQueryWrapper<Account> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Account::getUsername, accountAddReq.getUsername());

        List<Account> accounts = accountService.getBaseMapper().selectList(queryWrapper);

        if (accounts.size() > 0) {
            throw new FootBookException("用户名已存在");
        }

        String accountId = Util.getUUID32();
        LocalDateTime dateTime = LocalDateTime.now();

        // 权限对比
        // 获取基础权限（用于校验参数是否传递完整）
        List<AuthPermissionDTO> authPermissions = authPermissionService.getBaseMapper().getInitPermission();
        List<AuthPermissionDTO> authPermissionReqs = accountAddReq.getAuthPermissions();

        if (authPermissionReqs.size() != authPermissions.size()) {
            throw new FootBookException("权限信息缺失");
        }

        // 全权限id集合
        List<String> permissionIds = authPermissions.stream().map(AuthPermissionDTO::getId).collect(Collectors.toList());

        // 遍历校验
        for (AuthPermissionDTO authPermissionDTO : authPermissionReqs) {
            if (!permissionIds.contains(authPermissionDTO.getId())){
                throw new FootBookException("权限id信息错误");
            }
            // 正确
            AuthPermissionAccount authPermissionAccount = new AuthPermissionAccount();
            authPermissionAccount.setId(Util.getUUID32());
            authPermissionAccount.setAccountId(accountId);
            authPermissionAccount.setPermissionId(authPermissionDTO.getId());
            // 默认为false（没有权限）
            authPermissionAccount.setEnable(EmptyUtil.isEmpty(authPermissionDTO.getEnable()) ? false : authPermissionDTO.getEnable());
            authPermissionAccount.setStatus(false);
            authPermissionAccount.setCreateTime(dateTime);
            authPermissionAccount.setUpdateTime(dateTime);

            authPermissionAccountService.getBaseMapper().insert(authPermissionAccount);
        }


        // 新增account
        Account account = new Account();
        account.setId(accountId);
        account.setNickname(accountAddReq.getNickname());
        account.setUsername(accountAddReq.getUsername());
        account.setPassword(MD5Util.getMD5(accountAddReq.getPassword()));
        account.setInsertUid(adminId);
        account.setStatus(false);
        account.setCreateTime(dateTime);
        account.setUpdateTime(dateTime);

        accountService.getBaseMapper().insert(account);

        accessLogService.addLog("创建了账户：" + account.getUsername() + "");
    }

    /**
     * 删除用户
     *
     * @param accountDelReq
     */
    @Transactional
    public void accountDel(AccountDelReq accountDelReq) {
        checkMineAndThrow(accountDelReq.getId());
        // 查询用户
        Account account = accountService.getBaseMapper().selectById(accountDelReq.getId());
        if (account == null) {
            throw new FootBookException("用户不存在");
        }
        // 删除用户 account
        accountService.getBaseMapper().deleteById(account.getId());

        // 删除园区权限
        LambdaQueryWrapper<AuthPermissionAccount> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AuthPermissionAccount::getAccountId, accountDelReq.getId());
        authPermissionAccountService.getBaseMapper().delete(queryWrapper);

        // 踢人下线
        StpUtil.kickout(accountDelReq.getId());

        accessLogService.addLog("删除了账户：" + account.getUsername() + "");
    }

    /**
     * @return void
     * @Author whenjun
     * @Description 修改用户密码
     * @Date 16:18:42 2023/7/25 0025
     * @Param [accountResetPasswordReq]
     **/
    @Transactional
    public void accountResetPassword(AccountResetPasswordReq accountResetPasswordReq) {
        checkMineAndThrow(accountResetPasswordReq.getId());
        // 查询用户
        Account account = accountService.getBaseMapper().selectById(accountResetPasswordReq.getId());
        if (account == null) {
            throw new FootBookException("用户不存在");
        }

        account.setPassword(MD5Util.getMD5(accountResetPasswordReq.getPassword()));
        account.setUpdateTime(LocalDateTime.now());

        accountService.getBaseMapper().updateById(account);

        // 踢人下线
        StpUtil.kickout(accountResetPasswordReq.getId());

        accessLogService.addLog("修改了账户：" + account.getUsername() + "  的密码");
    }


    /**
     * 修改用户名或者昵称
     *
     * @param accountUpdNameReq
     */
    @Transactional
    public void accountUpdName(AccountUpdNameReq accountUpdNameReq) {

        // 查询用户
        Account account = accountService.getBaseMapper().selectById(accountUpdNameReq.getId());
        if (account == null) {
            throw new FootBookException("用户不存在");
        }

        if (!EmptyUtil.isEmpty(accountUpdNameReq.getUsername())) {
            account.setUsername(accountUpdNameReq.getUsername());

            accessLogService.addLog("修改了账户 " + account.getUsername() + " 的用户名为 " + account.getUsername());
        }

        if (!EmptyUtil.isEmpty(accountUpdNameReq.getNickname())) {
            account.setNickname(accountUpdNameReq.getNickname());

            accessLogService.addLog("修改了账户 " + account.getUsername() + " 的昵称为 " + account.getNickname());
        }

        accountService.getBaseMapper().updateById(account);
    }


    @Transactional
    public void accountUpd(AccountUpd accountUpd) {
        checkMineAndThrow(accountUpd.getId());
        // 查询用户
        Account account = accountService.getBaseMapper().selectById(accountUpd.getId());
        if (account == null) {
            throw new FootBookException("用户不存在");
        }

        if (!EmptyUtil.isEmpty(accountUpd.getUsername())) {
            account.setUsername(accountUpd.getUsername());

            accessLogService.addLog("修改了账户 " + account.getUsername() + " 的用户名为 " + account.getUsername());
        }

        if (!EmptyUtil.isEmpty(accountUpd.getNickname())) {
            account.setNickname(accountUpd.getNickname());

            accessLogService.addLog("修改了账户 " + account.getUsername() + " 的昵称为 " + account.getNickname());
        }

        if (!EmptyUtil.isEmpty(accountUpd.getPassword())) {
            // 密码强度校验
            if (!PasswordUtil.validatePassword2(accountUpd.getPassword())){
                throw new FootBookException("密码必须为大写英文+小写+数字+特殊符号的组合");
            }
            account.setPassword(MD5Util.getMD5(accountUpd.getPassword()));
            accessLogService.addLog("修改了账户：" + account.getUsername() + "  的密码");
        }
        account.setUpdateTime(LocalDateTime.now());

        // 更新权限
        if (!EmptyUtil.isEmpty(accountUpd.getAuthPermissions())){
            AccountPermissionUpdateReq accountPermissionUpdateReq = new AccountPermissionUpdateReq();
            accountPermissionUpdateReq.setId(accountUpd.getId());
            accountPermissionUpdateReq.setAuthPermissions(accountUpd.getAuthPermissions());

            accountPermissionUpdate(accountPermissionUpdateReq);
        }

        accountService.getBaseMapper().updateById(account);
        // 踢人下线
        StpUtil.kickout(accountUpd.getId());
    }


    @Transactional
    public void accountPermissionUpdate(AccountPermissionUpdateReq accountPermissionUpdateReq){
        Account account = accountService.getBaseMapper().selectById(accountPermissionUpdateReq.getId());

        if (account == null || "admin".equals(account.getType())){
            throw new FootBookException("id错误");
        }

        LocalDateTime dateTime = LocalDateTime.now();

        // 权限对比
        // 获取基础权限（用于校验参数是否传递完整）
        List<AuthPermissionDTO> authPermissions = authPermissionService.getBaseMapper().getInitPermission();
        List<AuthPermissionDTO> authPermissionsReqs = accountPermissionUpdateReq.getAuthPermissions();
        if (authPermissionsReqs.size() != authPermissions.size()){
            throw new FootBookException("权限信息缺失");
        }
        // 权限ids
        List<String> permissionIds = authPermissions.stream().map(AuthPermissionDTO::getId).distinct().collect(Collectors.toList());

        // 遍历校验
        for (AuthPermissionDTO authPermissionDTO : authPermissionsReqs) {
            if (!permissionIds.contains(authPermissionDTO.getId())){
                throw new FootBookException("园区权限信息错误");
            }
            // 信息正确 更新
            // 查询 AuthPermissionAccount
            LambdaQueryWrapper<AuthPermissionAccount> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(AuthPermissionAccount::getAccountId, accountPermissionUpdateReq.getId());
            queryWrapper.eq(AuthPermissionAccount::getPermissionId, authPermissionDTO.getId());

            AuthPermissionAccount authPermissionAccount = authPermissionAccountService.getBaseMapper().selectOne(queryWrapper);
            authPermissionAccount.setEnable(EmptyUtil.isEmpty(authPermissionDTO.getEnable()) ? false : authPermissionDTO.getEnable()); // 默认为false（没有权限）
            authPermissionAccount.setUpdateTime(dateTime);

            authPermissionAccountService.getBaseMapper().updateById(authPermissionAccount);
        }

        accessLogService.addLog("更新了“" + account.getUsername() + "”的权限");
    }

    @Transactional
    public void updatePassword(PasswordUpdate passwordUpdate) {

        // 密码强度校验
        if (!PasswordUtil.validatePassword2(passwordUpdate.getPassword())) {
            throw new FootBookException("密码必须为大写英文+小写+数字+特殊符号的组合");
        }

        String userId = (String) StpUtil.getLoginId();

        // 查询用户
        Account account = accountService.getBaseMapper().selectById(userId);

        String md5Pass = MD5Util.getMD5(passwordUpdate.getPassword());
        if (!md5Pass.equals(account.getPassword())) {
            throw new FootBookException("当前密码输入错误");
        }

        account.setPassword(MD5Util.getMD5(passwordUpdate.getNewPassword()));
        account.setUpdateTime(LocalDateTime.now());

        accountService.getBaseMapper().updateById(account);

        // 踢人下线
        StpUtil.kickout(userId);

        accessLogService.addLog(account.getUsername() + "修改了账户：" + account.getUsername() + "  的密码");
    }

    /**
     * 获取初始权限值
     *
     * @return
     */
    @Transactional
    public List<AuthPermissionDTO> getInitPermission() {
        List<AuthPermissionDTO> authPermissionDTOS = authPermissionService.getBaseMapper().getInitPermission();
        return authPermissionDTOS;
    }

    public void checkMineAndThrow(String userId){
        String mineId = SaTokenUtil.getUserId();
        if (mineId.equals(userId)) {
            throw new FootBookException("操作对象不能是自己");
        }
    }
}

